package cn.school.basics.service.impl;

import cn.school.basics.dao.BaseSpaceLocationDao;
import cn.school.basics.dao.DormitoryBerthDao;
import cn.school.basics.service.BaseSpaceLocationService;
import cn.school.basics.vo.BaseSpaceLocationVO;
import cn.school.basics.vo.DormitoryBerthVO;
import cn.school.basics.vo.LocationTreeNode;
import cn.school.common.utils.SysUserUtils;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

@Service
public class BaseSpaceLocationServiceImpl extends ServiceImpl<BaseSpaceLocationDao, BaseSpaceLocationVO> implements BaseSpaceLocationService {

    @Resource
    private DormitoryBerthDao dormitoryBerthDao;

    @Override
    public IPage<BaseSpaceLocationVO> findBaseSpaceLocationPageList(BaseSpaceLocationVO vo) {
        // 创建一个 LambdaQueryWrapper 对象，用于构建查询条件
        LambdaQueryWrapper<BaseSpaceLocationVO> wrapper = new LambdaQueryWrapper<>();

        // 如果查询条件中的地点名称不为空，添加一个 like 查询条件
        if (!StringUtils.isEmpty(vo.getLocationName())) {
            wrapper.like(BaseSpaceLocationVO::getLocationName, vo.getLocationName());
        }

        // 如果查询条件中的地点父 ID 不为空，添加一个等于查询条件
        if (!StringUtils.isEmpty(vo.getLocationPid())) {
            wrapper.eq(BaseSpaceLocationVO::getLocationPid, vo.getLocationPid());
        }

        // 如果查询条件中的地点类型不为空，添加一个等于查询条件
        if (!StringUtils.isEmpty(vo.getLocationType())) {
            wrapper.eq(BaseSpaceLocationVO::getLocationType, vo.getLocationType());
        }

        // 添加一个等于查询条件，查询当前租户的数据
        wrapper.eq(BaseSpaceLocationVO::getTenantId, SysUserUtils.getSysUser().getTenantId());

        // 按照地点父 ID 和地点名称进行升序排序
        wrapper.orderByAsc(BaseSpaceLocationVO::getLocationPid);
        wrapper.orderByAsc(BaseSpaceLocationVO::getLocationName);

        // 分页查询符合条件的数据
        IPage<BaseSpaceLocationVO> page = page(new Page<>(vo.getPageNum(), vo.getPageSize()), wrapper);

        int count = 0;
        // 遍历查询结果，判断每个地点是否有子节点
//        for (int i = 0; i < page.getRecords().size(); i++) {
//            BaseSpaceLocationVO rVO = page.getRecords().get(i);
//            LambdaQueryWrapper<BaseSpaceLocationVO> wrapperChild = new LambdaQueryWrapper<>();
//            wrapperChild.eq(BaseSpaceLocationVO::getLocationPid, rVO.getId());
//
//            // 添加一个等于查询条件，查询当前租户的数据
//            wrapperChild.eq(BaseSpaceLocationVO::getTenantId, SysUserUtils.getSysUser().getTenantIdToLong());
//
//            // 查询当前地点的子节点数量
//            count = this.baseMapper.selectCount(wrapperChild);
//
//            // 如果当前地点有子节点，设置 hasChildren 属性为 true
//            if (count > 0) {
//                rVO.setHasChildren(true);
//                rVO.setLevelNum(count);
//            }
//        }

        // 返回查询结果
        return page;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addOrUpdateBaseSpaceLocationInfo(BaseSpaceLocationVO vo) {

        String userName = SysUserUtils.getSysUser().getUsername();
        int num = 0;
        if (StringUtils.isEmpty(vo.getId())) {
            vo.setCreateBy(userName);
            vo.setCreateTime(new Date());
            num = this.baseMapper.insert(vo);
            if ("6".equals(vo.getLocationType())) {//添加宿舍时要添加床位
                for (DormitoryBerthVO berthVO : vo.getLocationList()) {
                    berthVO.setLocationId(String.valueOf(vo.getId()));
                    berthVO.setStatus("1");
                    berthVO.setCreateBy(userName);
                    berthVO.setCreateTime(new Date());
                    dormitoryBerthDao.insert(berthVO);
                }
            }
            if(vo.getNum() != null){
                if (vo.getLevelNum() == null || vo.getLevelNum() < vo.getNum()) {
                    for (int i = 0; i < (vo.getNum() - (vo.getLevelNum() != null ? vo.getLevelNum() : 0)); i++) {
                        buildingAddOrUpdate(vo);
                    }
                }
            }
        } else {
            vo.setModifyBy(userName);
            vo.setModifyTime(new Date());
            num = this.baseMapper.updateById(vo);
            updateDormitoryBerthInfo(vo, userName);
            if(vo.getNum() != null){

                if (vo.getLevelNum() == null || vo.getLevelNum() < vo.getNum()) {
                    for (int i = 0; i < (vo.getNum() - (vo.getLevelNum() != null ? vo.getLevelNum() : 0)); i++) {
                        buildingAddOrUpdate(vo);
                    }
                }
                if (vo.getLevelNum() > vo.getNum()) {
                    for (int i = 0; i < (vo.getLevelNum() - vo.getNum()); i++) {
                        Long max = 0L;
                        List<BaseSpaceLocationVO> buildingSonList = findBuildingSon(vo.getId());
                        for (BaseSpaceLocationVO base : buildingSonList) {
                            if (base.getId() > max) {
                                max = base.getId();
                            }
                        }
                        buildingDelete(max.intValue());
                    }
                }
            }
        }
        return num;
    }

    private void updateDormitoryBerthInfo(BaseSpaceLocationVO vo, String userName) {

        if ("6".equals(vo.getLocationType())) {//添加宿舍时要添加床位
            LambdaQueryWrapper<DormitoryBerthVO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DormitoryBerthVO::getLocationId, vo.getId());
            //删除原有床位，再新增
            dormitoryBerthDao.delete(wrapper);
            for (DormitoryBerthVO berthVO : vo.getLocationList()) {
                berthVO.setLocationId(String.valueOf(vo.getId()));
                berthVO.setStatus("1");
                berthVO.setCreateBy(userName);
                berthVO.setCreateTime(new Date());
                berthVO.setModifyBy(userName);
                berthVO.setModifyTime(new Date());
                dormitoryBerthDao.insert(berthVO);
            }
        }
    }


    @Override
    public int deleteBaseSpaceLocationInfo(BaseSpaceLocationVO vo) {
        LambdaQueryWrapper<BaseSpaceLocationVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BaseSpaceLocationVO::getLocationPid, vo.getId());
        int count = this.baseMapper.selectCount(wrapper);
        if (count > 0) {
            return -1;
        }
        return this.baseMapper.deleteById(vo.getId());
    }

    @Override
    public BaseSpaceLocationVO findSpaceLocationDetails(Long id) {
        return this.baseMapper.selectById(id);
    }

    @Override
    public List<LocationTreeNode> geNodeTree() {
        LambdaQueryWrapper<BaseSpaceLocationVO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BaseSpaceLocationVO::getStatus, 1);
        queryWrapper.orderByAsc(BaseSpaceLocationVO::getLevel);
        List<BaseSpaceLocationVO> list = this.baseMapper.selectList(queryWrapper);
        List<LocationTreeNode> levelOneList = new ArrayList<>();
        Map<Long, LocationTreeNode> transCalcMap = new HashMap<Long, LocationTreeNode>();
        LocationTreeNode node = null;
        LocationTreeNode parentNode = null;
        for (BaseSpaceLocationVO baseSpaceLocationVO : list) {
            if ("1".equals(baseSpaceLocationVO.getLevel()) && baseSpaceLocationVO.getLocationPid() != null && 0 == baseSpaceLocationVO.getLocationPid()) {
                node = new LocationTreeNode();
                node.init(baseSpaceLocationVO);
                levelOneList.add(node);
            } else if (transCalcMap.containsKey(baseSpaceLocationVO.getLocationPid())) {
                parentNode = transCalcMap.get(baseSpaceLocationVO.getLocationPid());
                node = parentNode.addChildren(baseSpaceLocationVO);
            }
            transCalcMap.put(node.getId(), node);
        }
        return levelOneList;
    }

    @Override
    public Map<Long, String> getNodeAllDirNameMap() {
        LambdaQueryWrapper<BaseSpaceLocationVO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BaseSpaceLocationVO::getStatus, 1);
        queryWrapper.orderByAsc(BaseSpaceLocationVO::getLevel);
        List<BaseSpaceLocationVO> list = this.baseMapper.selectList(queryWrapper);
        //key:id;
        //value:level1name/; level1name/level2name; level1name/level2name/leve32name/
        Map<Long, String> transCalcNameMap = new HashMap<Long, String>();
        if (list != null && list.size() != 0) {
            for (BaseSpaceLocationVO baseSpaceLocationVO : list) {
                if (transCalcNameMap.containsKey(baseSpaceLocationVO.getLocationPid())) {
                    transCalcNameMap.put(baseSpaceLocationVO.getId(), transCalcNameMap.get(baseSpaceLocationVO.getLocationPid()) + "/" + baseSpaceLocationVO.getLocationName());
                } else {
                    transCalcNameMap.put(baseSpaceLocationVO.getId(), baseSpaceLocationVO.getLocationName());
                }
            }
        }

        return transCalcNameMap;
    }

    @Override
    public List<Long> getNodeAllDirPidList(Long id) {
        LambdaQueryWrapper<BaseSpaceLocationVO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BaseSpaceLocationVO::getStatus, 1);
        queryWrapper.orderByAsc(BaseSpaceLocationVO::getLevel);
        List<BaseSpaceLocationVO> list = this.baseMapper.selectList(queryWrapper);
        //key:id;
        //value:level1name/; level1name/level2name; level1name/level2name/leve32name/
        Map<Long, List<Long>> transCalcNameMap = new HashMap<Long, List<Long>>();
        List<Long> tempList = null;
        if (list != null && list.size() != 0) {
            for (BaseSpaceLocationVO baseSpaceLocationVO : list) {
                if (transCalcNameMap.containsKey(baseSpaceLocationVO.getLocationPid())) {
                    tempList = new ArrayList<>();
                    tempList.addAll(transCalcNameMap.get(baseSpaceLocationVO.getLocationPid()));
                    tempList.add(baseSpaceLocationVO.getId());
                    transCalcNameMap.put(baseSpaceLocationVO.getId(), tempList);
                } else {
                    tempList = new ArrayList<>();
                    tempList.add(baseSpaceLocationVO.getId());
                    transCalcNameMap.put(baseSpaceLocationVO.getId(), tempList);
                }
            }
        }

        return transCalcNameMap.get(id);
    }

    @Override
    public List<BaseSpaceLocationVO> locationTypeList(String type) {
        LambdaQueryWrapper<BaseSpaceLocationVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BaseSpaceLocationVO::getLocationType, type);
        wrapper.eq(BaseSpaceLocationVO::getStatus, "1");
        wrapper.orderByAsc(BaseSpaceLocationVO::getLocationName);
        return this.baseMapper.selectList(wrapper);
    }

    @Override
    public BaseSpaceLocationVO locationDetails(String id) {
        BaseSpaceLocationVO vo = this.baseMapper.selectById(id);
        if (vo != null) {
            LambdaQueryWrapper<DormitoryBerthVO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DormitoryBerthVO::getLocationId, id);
            wrapper.eq(DormitoryBerthVO::getStatus, "1");
            List<DormitoryBerthVO> berthVOList = dormitoryBerthDao.selectList(wrapper);
            vo.setLocationList(berthVOList);
        }
        return vo;
    }

    @Override
    public List<DormitoryBerthVO> getDormitoryBerthList(String locationId) {
        LambdaQueryWrapper<DormitoryBerthVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DormitoryBerthVO::getLocationId, locationId);
        wrapper.eq(DormitoryBerthVO::getStatus, "1");
        wrapper.and((queryWrapper) -> {
            queryWrapper.isNull(DormitoryBerthVO::getUseStudentId)
                    .or()
                    .eq(DormitoryBerthVO::getUseStudentId, "");
        });
        List<DormitoryBerthVO> berthVOList = dormitoryBerthDao.selectList(wrapper);
        return berthVOList;
    }

    @Override
    public int updateDed(DormitoryBerthVO vo) {
        if (StringUtils.isEmpty(vo.getId())) {
            return 0;
        }
        //修改原宿舍使用人为空
        LambdaQueryWrapper<DormitoryBerthVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DormitoryBerthVO::getUseStudentId, vo.getUseStudentId());
        DormitoryBerthVO oldVO = new DormitoryBerthVO();
        oldVO.setUseStudentId("");
        dormitoryBerthDao.update(oldVO, wrapper);
        return dormitoryBerthDao.updateById(vo);
    }

    @Override
    public List<BaseSpaceLocationVO> findBuildingSon(Long pid) {
        LambdaQueryWrapper<BaseSpaceLocationVO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BaseSpaceLocationVO::getLocationPid, pid);
        // 添加一个等于查询条件，查询当前租户的数据
        wrapper.eq(BaseSpaceLocationVO::getTenantId, SysUserUtils.getSysUser().getTenantId());
        if (pid != 0) {
            wrapper.eq(BaseSpaceLocationVO::getLocationType, 2);
        }
        List<BaseSpaceLocationVO> list = baseMapper.selectList(wrapper);
        return list;
    }

    @Override
    public BaseSpaceLocationVO buildingAddOrUpdate(BaseSpaceLocationVO vo) {
        String userName = SysUserUtils.getSysUser().getUsername();
        vo.setCreateBy(userName);
        vo.setCreateTime(new Date());
        if (vo.getLocationPid() == 0) {
            LambdaQueryWrapper<BaseSpaceLocationVO> wrapper=new LambdaQueryWrapper<>();
            wrapper.eq(BaseSpaceLocationVO::getLocationPid, vo.getId());
            List<BaseSpaceLocationVO> locationVOList = baseMapper.selectList(wrapper);
            BaseSpaceLocationVO newVo = new BaseSpaceLocationVO();
            newVo.setCreateBy(userName);
            newVo.setSchoolId(vo.getSchoolId());
            newVo.setLevelName(vo.getLocationName() + "-" + (locationVOList.size()+1) + "楼");
            newVo.setLocationName((locationVOList.size()+1)+"楼");
            newVo.setLevel((locationVOList.size()+1)+"");
            newVo.setStatus("1");
            newVo.setLocationType("2");
            newVo.setLocationPid(vo.getId());
            baseMapper.insert(newVo);
            return null;
        }
        return null;
    }

    @Override
    public BaseSpaceLocationVO buildingDelete(BaseSpaceLocationVO vo) {
        if (baseMapper.deleteById(vo.getId())>0) {
            return vo;
        }
        return null;
    }

    @Override
    public boolean buildingDelete(Integer id) {
        if (baseMapper.deleteById(id) > 0) {
            return true;
        }
        return false;
    }
}
